# dbus_simulator.py
import serial
import time
import struct
import random

class DBusSimulator:
    def __init__(self, port='COM3', baudrate=115200):
        self.port = port
        self.baudrate = baudrate
        self.ser = None
        
        # 通道值范围
        self.CH_MIN = 364
        self.CH_MID = 1024
        self.CH_MAX = 1684
        
        # 当前状态 - 只需要6个有效通道，不是14个！
        self.channels = [self.CH_MID] * 6  # 修正：6个通道
        self.switches = 0
        
        # 尝试连接串口
        self.connect_serial()
    
    def connect_serial(self):
        """连接串口"""
        try:
            self.ser = serial.Serial(
                port=self.port,
                baudrate=self.baudrate,
                bytesize=serial.EIGHTBITS,
                parity=serial.PARITY_NONE,
                stopbits=serial.STOPBITS_ONE,
                timeout=1
            )
            time.sleep(0.5)
            print(f"✓ 成功连接到 {self.port}")
            return True
        except Exception as e:
            print(f"✗ 连接 {self.port} 失败: {e}")
            self.ser = None
            return False
    
    def pack_data(self):
        """打包DBUS数据帧 - 修正为18字节"""
        data = bytearray([0x03, 0x3F])  # 帧头: 2字节
        
        # 6个通道数据: 6×2=12字节
        for ch in self.channels:
            data.extend(struct.pack('<H', ch))
        
        # 2个保留字节 (位置14-15)
        data.extend([0x00, 0x00])
        
        # 开关状态: 1字节
        data.append(self.switches)
        
        # 鼠标按键: 1字节
        data.append(0)
        
        # 验证长度
        if len(data) != 18:
            print(f"警告: 数据帧长度错误! 期望18字节, 实际{len(data)}字节")
        
        return data
    
    def set_channel(self, channel, value):
        """设置通道值 (-660 ~ 660)"""
        if 0 <= channel < 6:  # 修正：只有6个通道
            raw_value = max(min(value + self.CH_MID, self.CH_MAX), self.CH_MIN)
            self.channels[channel] = raw_value
            return True
        else:
            print(f"错误: 通道号 {channel} 无效 (0-5)")
            return False
    
    def set_switch(self, switch_num, position):
        """设置开关状态"""
        if switch_num == 0:  # 左开关
            self.switches = (self.switches & 0xFC) | (position & 0x03)
            return True
        elif switch_num == 1:  # 右开关
            self.switches = (self.switches & 0xF3) | ((position & 0x03) << 2)
            return True
        else:
            print(f"错误: 开关号 {switch_num} 无效")
            return False
    
    def send_data(self):
        """发送数据帧"""
        if not self.ser or not self.ser.is_open:
            print("✗ 串口未连接")
            return None
        
        try:
            data = self.pack_data()
            bytes_written = self.ser.write(data)
            if bytes_written == len(data):
                return data
            else:
                print(f"✗ 发送不完整: {bytes_written}/{len(data)} 字节")
                return None
        except Exception as e:
            print(f"✗ 发送失败: {e}")
            return None
    
    def create_test_scenario(self, scenario):
        """创建测试场景"""
        # 重置所有通道到中位
        for i in range(6):
            self.set_channel(i, 0)
        
        if scenario == "neutral":
            self.set_switch(0, 1)  # 左开关中位
            self.set_switch(1, 1)  # 右开关中位
            print("✓ 中位测试场景")
        elif scenario == "forward_left":
            self.set_channel(2, 500)   # 左Y向前
            self.set_channel(3, -300)  # 左X向左
            self.set_switch(0, 0)      # 左开关向上
            print("✓ 前进左转场景")
        elif scenario == "emergency_stop":
            self.set_switch(1, 2)      # 右开关向下(急停模式)
            print("✓ 急停场景")
    
    def display_status(self):
        """显示当前状态"""
        channel_names = ["右X", "右Y", "左Y", "左X", "拨轮1", "拨轮2"]
        
        print("\n当前通道状态:")
        for i in range(6):
            control_value = self.channels[i] - 1024
            print(f"  {channel_names[i]}: {control_value:4d}")
        
        left_sw = self.switches & 0x03
        right_sw = (self.switches >> 2) & 0x03
        print(f"开关状态: 左={left_sw}, 右={right_sw}")

def main():
    print("DBUS遥控器数据模拟器 (18字节协议)")
    print("=" * 50)
    
    simulator = DBusSimulator(port='COM3', baudrate=115200)
    
    if not simulator.ser or not simulator.ser.is_open:
        print("程序退出")
        return
    
    print("\n通道映射:")
    print("  0-右X, 1-右Y, 2-左Y, 3-左X, 4-拨轮1, 5-拨轮2")
    print("开关: 0-左开关, 1-右开关 (0=上,1=中,2=下)")
    
    try:
        while True:
            print("\n" + "=" * 40)
            simulator.display_status()
            print("-" * 40)
            print("1. 中位测试")
            print("2. 前进左转") 
            print("3. 急停测试")
            print("4. 自定义设置")
            print("0. 退出")
            
            choice = input("选择: ").strip()
            
            if choice == '1':
                simulator.create_test_scenario("neutral")
            elif choice == '2':
                simulator.create_test_scenario("forward_left")
            elif choice == '3':
                simulator.create_test_scenario("emergency_stop")
            elif choice == '4':
                try:
                    ch = int(input("通道(0-5): "))
                    val = int(input("值(-660~660): "))
                    if not simulator.set_channel(ch, val):
                        continue
                    
                    sw = int(input("开关(0-左,1-右): "))
                    pos = int(input("位置(0-上,1-中,2-下): "))
                    if not simulator.set_switch(sw, pos):
                        continue
                except ValueError:
                    print("输入错误")
                    continue
            elif choice == '0':
                break
            else:
                print("无效选择")
                continue
            
            # 发送数据
            data = simulator.send_data()
            if data:
                print(f"✓ 发送成功: {len(data)} 字节")
                print(f"  数据: {data.hex()}")
            
            time.sleep(0.5)
            
    except KeyboardInterrupt:
        print("\n程序中断")
    
    finally:
        if simulator.ser:
            simulator.ser.close()
            print("串口已关闭")

if __name__ == "__main__":
    main()